package jp.co.toshiba.ffsa.service.csde;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.Key;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.List;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;

import jp.co.toshiba.ffsa.entity.AttachedFile;
import jp.co.toshiba.ffsa.entity.Project;
import jp.co.toshiba.ffsa.entity.System;
import jp.co.toshiba.ffsa.service.common.ConstantValue;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.struts.upload.FormFile;
import org.seasar.extension.jdbc.JdbcManager;
import org.seasar.extension.jdbc.where.SimpleWhere;
import org.seasar.framework.container.SingletonS2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.struts.util.MessageResourcesUtil;

/**
 * 設計I/F - 設計書アップロード画面 サービスクラス
 * @author npc
 */
public class Csde401Service {
    /** プロジェクトID */
    public String projectId;
    /** ワークフローID */
    public String workflowId;
    /** レビジョン */
    public String revision;
    /** システム第3キー */
    public String systemId3;
    /** ファイルリスト */
    public List<System> fileList = null;
    /** ファイルチェックリスト */
    public List<System> checkList = null;
    /** ユーザーID */
    private String userId;
    /** エラーコード */
    private String errorCode;
    /** ディレクトリ名 */
    private String dir;
    /** ファイルパス */
    public String path;
    /** ファイル拡張子 */
    public String fileNameExtension;
    /** ファイルサイズ */
    public String fileSize;
    /** ファイル名 */
    public String fileName;
    /** ファイルリストタイトル */
    public String listTitle;
    /** プロジェクトエンティティ */
    private Project project;
    /** ファイルセットタイプ */
    public String filesetType;

    /**
     * ワークフローで必要なアップロードファイルの一覧を取得
     * @return List<System>
     */
    public List<System> getFileList() {

        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 検索条件
        SimpleWhere swh = new SimpleWhere().eq("systemId1", "design_data_in")
                                           .eq("systemId2", workflowId)
                                           .eq("deleteFlag", ConstantValue.deleteFlagEnabled)
                                           ;

        // アップロードファイルの一覧情報取得
        fileList  = jdbcManager.from(System.class)
                                             .where(swh)
                                             .orderBy("seq")
                                             .getResultList()
                                             ;
        return fileList;
    }

    /**
     * アップロードファイルのチェック情報取得
     * ファイルチェックを行う
     * @param file
     * @throws Exception
     */
    public Boolean checkFile(FormFile file) throws Exception {

        String[] fileExtensions = null;
        String fileExtension    = "";
        int first               = 0;
        int successCount        = 0;

        // アップロードファイルのチェック情報取得
        if(!checkInfo()){
            errorCode = "csde401.900";
            return false;
        }else{
            for (int i = 0; i < checkList.size(); i++) {
                // ファイル拡張子のチェック
                if( !("".equals(checkList.get(i).value2) || checkList.get(i).value2 == null) ) {
                    if("".equals(file.getFileName())){
                        listTitle = checkList.get(i).value1;
                        errorCode = "errors.required";
                        return false;
                    }else{
                        fileExtensions  = checkList.get(i).value2.split(",");
                        first           = file.getFileName().indexOf(".");
                        fileExtension   = file.getFileName().substring( (first + 1), file.getFileName().length());
                        for (int j = 0; j < fileExtensions.length; j++) {
                            if( fileExtension.equals(fileExtensions[j]) ){
                                successCount += 1;
                            }
                        }
                        if(successCount < 1){
                            fileNameExtension = checkList.get(i).value2;
                            errorCode = "csde401.901";
                            return false;
                        }
                    }
                }

                // ファイルサイズのチェック
                if( "".equals(checkList.get(i).value3) || checkList.get(i).value3 == null ){
                    errorCode = "csde401.900";
                    return false;
                }else{
                    if ( file.getFileSize() == 0 ) {
                        fileName  = file.getFileName();
                        errorCode = "csde401.903";
                        return false;
                    }else if( file.getFileSize() > Integer.valueOf(checkList.get(i).value3) ){
                        fileSize  = fileSize(checkList.get(i).value3);
                        errorCode = "csde401.902";
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * ディレクトリ生成
     * @param file
     * @throws Exception
     */
    public void makeDirs(FormFile file) throws Exception {
        dir = MessageResourcesUtil.getMessage("designInterface.project.folderPath");
        dir = dir + projectId + "/" + workflowId + "/" + revision + "/in";
        path = "";
        File dirs = new File(dir);
        if (!dirs.exists()) {
            dirs.mkdirs();  //make folders
        }
        path = dirs + "/" + file.getFileName();
    }

    /**
     * アップロードされたデータを暗号化したファイルに書き出します。
     *
     * @param path
     *            ファイルのパス
     * @param formFile
     *            アップロードされたデータ
     * @throws Exception
     */
    public void writeFile(FormFile file) throws Exception {

        InputStream        is  = null;
        FileOutputStream   fos = null;
        CipherOutputStream cos = null;
        
        is = file.getInputStream();
        Key key = new SecretKeySpec(DigestUtils.sha256(ConstantValue.key), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        fos = new FileOutputStream(path);
        cos = new CipherOutputStream(fos, cipher);

        fos.write(cipher.getIV());

        byte[] a = new byte[8];
        int i = is.read(a);

        while (i != -1) {
        	cos.write(a, 0, i);
        	i = is.read(a);
        }

        cos.flush();
        IOUtils.closeQuietly(is);
        IOUtils.closeQuietly(fos);
        IOUtils.closeQuietly(cos);

    }

    /**
     * アップロードファイルのチェック情報取得
     */
    public Boolean checkInfo(){
        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 検索条件
        SimpleWhere swh = new SimpleWhere().eq("systemId1", "design_data_in")
                                           .eq("systemId2", workflowId)
                                           .eq("systemId3", systemId3)
                                           .eq("deleteFlag", ConstantValue.deleteFlagEnabled)
                                           ;

        // アップロードファイルのチェック情報取得
        checkList  = jdbcManager.from(System.class)
                                             .where(swh)
                                             .orderBy("seq")
                                             .getResultList()
                                             ;
        if(checkList.size() < 0){
            return false;
        }
        return true;

    }

    /**
     * アップロードファイルの情報がattached_fileテーブルに存在するかチェック
     * @return true:存在しない false:存在する
     */
    public Boolean checkAttachedFile() {

        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 検索条件
        SimpleWhere swh = new SimpleWhere().eq("projectId", projectId)
                                           .eq("workflowId", workflowId)
                                           .eq("revision", Integer.valueOf(revision))
                                           .eq("inOut", "IN")
                                           .eq("dataType", systemId3)
                                           ;

        // アップロードファイルのデータ件数取得
        long count = jdbcManager.from(AttachedFile.class)
                                .where(swh)
                                .getCount()
                                ;

        if(count > 0){
            return false;
        }
        return true;
    }

    /**
     * アップロードしたファイルの情報をattached_fileテーブルに登録する
     * @param file
     * @throws Exception
     */
    public void insertAttachedFile(FormFile file) throws Exception{
        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 当日取得
        Calendar cal = Calendar.getInstance();
        Timestamp sysDateTime = new Timestamp(cal.getTime().getTime());

        AttachedFile attachedFile = new AttachedFile();
        for (int j = 0; j < checkList.size(); j++) {
            attachedFile.projectId      = projectId;
            attachedFile.workflowId     = workflowId;
            attachedFile.revision       = Integer.valueOf(revision);
            attachedFile.inOut          = "IN";
            attachedFile.dataType       = systemId3;
            attachedFile.fileName       = file.getFileName();
            attachedFile.filePath       = dir;
            attachedFile.fileSize       = Integer.valueOf(file.getFileSize());
            attachedFile.attachedAt     = sysDateTime;
            attachedFile.createdAt      = sysDateTime;
            attachedFile.createdBy      = userId;
            attachedFile.updatedAt      = sysDateTime;
            attachedFile.updatedBy      = userId;
            attachedFile.deleteFlag     = ConstantValue.deleteFlagEnabled;
            // 登録
            jdbcManager.insert(attachedFile).includes("projectId"
                                                ,"workflowId"
                                                ,"revision"
                                                ,"inOut"
                                                ,"dataType"
                                                ,"fileName"
                                                ,"filePath"
                                                ,"fileSize"
                                                ,"attachedAt"
                                                ,"createdAt"
                                                ,"createdBy"
                                                ,"updatedAt"
                                                ,"updatedBy"
                                                ,"deleteFlag"
                                                ).execute()
                                                ;
        }
    }

    /**
     * ファイル情報更新
     * @param file
     * @throws Exception
     */
    public void updateAttachedFile(FormFile file) throws Exception{

        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 現在日時取得
        Calendar cal = Calendar.getInstance();
        Timestamp sysDateTime = new Timestamp(cal.getTime().getTime());

        AttachedFile attachedFile = new AttachedFile();

        for (int j = 0; j < checkList.size(); j++) {
            attachedFile.projectId  = projectId;
            attachedFile.workflowId = workflowId;
            attachedFile.revision   = Integer.valueOf(revision);
            attachedFile.inOut      = "IN";
            attachedFile.dataType   = systemId3;
            attachedFile.fileName   = file.getFileName();
            attachedFile.filePath   = dir;
            attachedFile.fileSize   = Integer.valueOf(file.getFileSize());
            attachedFile.attachedAt = sysDateTime;
            attachedFile.updatedAt  = sysDateTime;
            attachedFile.updatedBy  = userId;
            attachedFile.deleteFlag = ConstantValue.deleteFlagEnabled;

            // 更新
            jdbcManager.update(attachedFile).includes( "fileName"
                                                     , "filePath"
                                                     , "fileSize"
                                                     , "attachedAt"
                                                     , "updatedAt"
                                                     , "updatedBy"
                                                     , "deleteFlag"
                                                     ).execute()
                                                     ;
        }
    }

    /**
     * 指定サイズを確認
     * @return fileSize ファイルサイズ
     */
    public String fileSize(String byteSize) {
        String fileSize = "";
        DecimalFormat decimalFormat =new DecimalFormat("#.##");

        long fileSizeByte   = Long.valueOf(byteSize);
        double fileSizeKB   = Double.valueOf(decimalFormat.format(fileSizeByte /1024));
        double fileSizeMB   = Double.valueOf(decimalFormat.format(fileSizeByte /(1024*1024)));
        double fileSizeGB   = Double.valueOf(decimalFormat.format(fileSizeByte /(1024*1024*1024)));

        if(fileSizeGB > 1){
            fileSize = (int) fileSizeGB + "G";
        }else if(fileSizeMB > 1){
            fileSize = (int) fileSizeMB + "M";
        }else if(fileSizeKB >1){
            fileSize = (int) fileSizeKB + "K";
        }else{
            fileSize =  String.valueOf(fileSizeByte) ;
        }
        return fileSize;
    }

    /**
     * workflowId = 2 の場合、
     * projectテーブルからFile setの設定値を取得
     */
    public Boolean getFilesetFromProject(){

        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 検索条件
        SimpleWhere swh = new SimpleWhere().eq("projectId", projectId)
                                           .eq("deleteFlag", ConstantValue.deleteFlagEnabled)
                                           ;

        // ile setの設定値を取得
        project  = jdbcManager.from(Project.class)
                                             .where(swh)
                                             .getSingleResult()
                                             ;
        if(project == null){
            return false;
        }
        return true;

    }

    /**
     * ワークフローで必要なアップロードファイルの一覧を取得
     * workflowId = 2 の場合、
     * 取得したfileset_typeの名称をsystemテーブルから取得する
     * @return System
     */
    public void getFilesetType() {

        // S2Container初期化
        SingletonS2ContainerFactory.init();

        // S2ContainerからJdbcManagerを取得
        JdbcManager jdbcManager = SingletonS2Container.getComponent(JdbcManager.class);

        // 検索条件
        SimpleWhere swh = new SimpleWhere().eq("systemId1", MessageResourcesUtil.getMessage("csde401.008"))
                                           .eq("systemId2", project.filesetType)
                                           .eq("deleteFlag", ConstantValue.deleteFlagEnabled)
                                           ;

        // アップロードファイルの一覧情報取得
        System system  = jdbcManager.from(System.class)
                                             .where(swh)
                                             .orderBy("seq")
                                             .getSingleResult()
                                             ;
        if( system != null){
            filesetType = system.value1;
        }

    }


    /**
     * @param userId セットする
     */
    public void setUserId(String userId) {this.userId = userId;}

    /**
     * @return errorCode
     */
    public String getErrorCode() {return errorCode;}

}
